package com.ips.service.impl;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.ips.service.IPV4Service;
import com.ips.utils.exception.OperationException;
import com.ips.vo.IPInfoIVO;
import com.ips.vo.IPInfoOVO;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class IPV4ServiceImpl implements IPV4Service {

    @Override
    public List<IPInfoOVO> getIPV4Info(IPInfoIVO ivo) {
        String ipContent = ivo.getIpContent();
        if (ObjectUtil.isEmpty(ipContent)) {
            // 爬取Ips段
            ipContent = getIps();
        }

        String[] contentList = StrUtil.subBetweenAll(ipContent, "\"");
        // ipInfo
        List<IPInfoOVO> ipInfoListOVO = new ArrayList<>();

        URL resource = ResourceUtil.getResource("ip/ip2region.xdb");
        String dbPath = resource.getPath();

        // 1、从 dbPath 加载整个 xdb 到内存。
        byte[] cBuff;
        try {
            cBuff = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
            log.debug("failed to load content from " + dbPath + ": " + e);
            throw new OperationException("failed to load content from " + dbPath + ": " + e);
        }

        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
        Searcher searcher;
        try {
            searcher = Searcher.newWithBuffer(cBuff);
        } catch (Exception e) {
            log.debug("failed to create content cached searcher: " + e);
            throw new OperationException("failed to create content cached searcher:" + e);
        }

        // 3、查询
        for (String content : contentList) {
            boolean contains = ReUtil.isMatch("^[^A-Za-z]*", content);
            if (contains) {
                String ip = StrUtil.subBefore(content, '/', false);
                try {
                    String region = searcher.search(ip);
                    // 处理region信息
                    if (ObjectUtil.isNotEmpty(region)) {
                        // 处理所有为0的改为空值
                        String regionReplace = StrUtil.replace(region, "0", "");
                        // 处理数据
                        List<String> split = StrUtil.split(regionReplace, "|");
                        if (ObjectUtil.isNotEmpty(split)) {
                            String country = split.get(0);
                            // 排除中国ip
                            if (ObjectUtil.equal(country, "中国")) {
                                continue;
                            }
                            IPInfoOVO ipInfoOVO = new IPInfoOVO();
                            ipInfoOVO.setIp(content);
                            ipInfoOVO.setCountry(country);
                            ipInfoOVO.setProvince(split.get(2));
                            ipInfoOVO.setCity(split.get(3));
                            ipInfoOVO.setIsp(split.get(4));
                            ipInfoListOVO.add(ipInfoOVO);
                        }
                    }
                } catch (Exception e) {
                    log.debug("failed to search(" + ip + "):" + e);
                    throw new OperationException("failed to search(" + ip + "):" + e);
                }
            }
        }

        // 4、关闭资源 - 该 searcher 对象可以安全用于并发，等整个服务关闭的时候再关闭 searcher
        try {
            searcher.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 备注：并发使用，用整个 xdb 数据缓存创建的查询对象可以安全的用于并发，也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。
        log.info("成功调用");
        return ipInfoListOVO;
    }


    /**
     * 获取Ip段
     *
     * @return Ip段
     */
    private String getIps() {
        try {
            // 目标地址
            String url = "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/LocationsOfEdgeServers.html";
            Document document = Jsoup.connect(url).timeout(5000).get();
            Element elementById = document.getElementById("main-col-body");

            Elements elements = elementById.getElementsByTag("p");
            // 第几位
            Integer size = null;
            for (int i = 0; i < elements.size(); i++) {
                Element element = elements.get(i);
                if (ObjectUtil.isNotEmpty(element.getElementsByClass("code"))) {
                    size = i + 1;
                    break;
                }
            }
            // 调用get接口获取数据
            String span = elements.get(size).getElementsByTag("span").get(0).text();

            return HttpUtil.get(span);
        } catch (IOException e) {
            throw new OperationException("Ip段获取失败，请自行查找Ip段");
        }
    }
}
